/********************************************************************************
* @file    bsp_lvd.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-12-18
* @brief   检测电源电压
流程：
1. 检测电源电压是否小于某设定值。
2. 如果小于设定值，则检测下一个阶梯
3. 如果下一个阶梯没有检测到，则电源电压取上一个阶梯值。

0：4.4V
1：4.0V
2：3.6V
3：3.3V
4：3.1V
5：2.9V
6：2.7V
7：2.5V
********************************************************************************/

#include "RTE_Components.h"
#include CMSIS_device_header
#include "cx32l003_hal.h"
#include <stdint.h>
#include <stdbool.h>

#include "app_main.h"

LVD_HandleTypeDef g_lvd_handle = {
    .Instance          = LVD,
    .Init.VoltageLevel = LVD_VOLLEVEL_4_4V,
    .Init.TriggerSel   = LVD_TRIGGER_RISING,     // 触发使能 VDD从低于阈值电压变为高于阈值电压
    .Init.Action       = LVD_ACTION_INTERRUPT,   // LVD中断复位0：产生中断
    .Init.FltNum       = 0x000F0000,             // 32.768K
    .Init.FltClkSel    = LVD_FLTCLK_LIRC         // 滤波时钟
};

bool g_lvd_init_flag     = false;
bool g_lvd_checking      = false;
uint16_t g_lvd_bat_vol   = false;

/**
 * @brief  初始化低电压检测
 */
void bsp_lvd_init(void)
{
    if (g_lvd_init_flag)
    {
        return;
    }
    g_lvd_init_flag = true;
    HAL_NVIC_EnableIRQ(LVD_IRQn);   // NVIC LVD中断使能
}

/**
 * @brief  关闭低电压检测
 */
void bsp_lvd_deinit(void)
{
    if (!g_lvd_init_flag)
    {
        return;
    }
    g_lvd_init_flag = false;
    HAL_LVD_DeInit(&g_lvd_handle);
    __HAL_RCC_LVDVC_CLK_DISABLE();
}

uint16_t get_lvd_vol_val(void)
{
    return g_lvd_bat_vol;
}

/**
 * @brief  得到上一个阶梯电源电压
 * @note   必须是下个阶梯没有检测到中断，该函数获取值才有效。
 * @retval 返回得到上一个阶梯电源电压
 */
uint16_t get_lvd_check_vol_val(void)
{
    if(g_lvd_handle.Init.VoltageLevel == LVD_VOLLEVEL_4_4V)
    {
        return 4400;
    }
    switch (g_lvd_handle.Init.VoltageLevel-1)
    {
        case LVD_VOLLEVEL_4_4V:
            return 4400;
        case LVD_VOLLEVEL_4_0V:
            return 4000;
        case LVD_VOLLEVEL_3_6V:
            return 3600;
        case LVD_VOLLEVEL_3_3V:
            return 3300;
        case LVD_VOLLEVEL_3_1V:
            return 3100;
        case LVD_VOLLEVEL_2_9V:
            return 2900;
        case LVD_VOLLEVEL_2_7V:
            return 2700;
        case LVD_VOLLEVEL_2_5V:
            return 2500;
        default:
            return 0;
    }
}

/**
 * @brief  开始低电压检测
 * @note   从4.4V开始检测
 */
void bsp_lvd_start_check(void)
{
    if (!g_lvd_init_flag)
    {
        return;
    }
    if (g_lvd_checking)
    {
        g_lvd_bat_vol = get_lvd_check_vol_val();
        g_lvd_checking = false;
        main_send_signal(SIGNAL_ADC_COLLECTION);
        return;
    }
    g_lvd_checking = true;
    __HAL_RCC_LVDVC_CLK_ENABLE();
    g_lvd_handle.Init.VoltageLevel = LVD_VOLLEVEL_4_4V;
    HAL_LVD_Init(&g_lvd_handle);

    HAL_NVIC_EnableIRQ(LVD_IRQn);     // NVIC LVD中断使能
    HAL_LVD_Enable_IT(&g_lvd_handle); // LVD使能
}

/**
 * @brief  依次低电压检测,由中断回调,逐级逼近真实电源。
 * @note   从4.4V开始检测
 */
void bsp_lvd_process_check(void)
{
    if (!g_lvd_init_flag)
    {
        return;
    }
    __HAL_RCC_LVDVC_CLK_ENABLE();
    // 逐级逼近真实电源
    g_lvd_handle.Init.VoltageLevel += 1;
    if (g_lvd_handle.Init.VoltageLevel > LVD_VOLLEVEL_2_5V)
    {
        g_lvd_handle.Init.VoltageLevel = LVD_VOLLEVEL_2_5V;
        g_lvd_bat_vol = 2500;
        g_lvd_checking = false;
        main_send_signal(SIGNAL_ADC_COLLECTION);
        return;
    }
    HAL_LVD_Init(&g_lvd_handle);

    HAL_NVIC_EnableIRQ(LVD_IRQn);     // NVIC LVD中断使能
    HAL_LVD_Enable_IT(&g_lvd_handle); // LVD使能
}

/**
  * @brief This function handles LVD Interrupt .
  */
void LVD_IRQHandler(void)
{
    HAL_LVD_IRQHandler(&g_lvd_handle);
}

/**
 * @brief  Interrupt callback in non blocking mode
 * @param  htim : LVD handle
 */
void HAL_LVD_InterruptCallback(LVD_HandleTypeDef *hlvd)
{
    main_send_signal(SIGNAL_LVD_CHECK);
}
